import json
import os
import re

from jinja2 import Environment, FileSystemLoader
from sqlalchemy import MetaData

from apps.tool import underline_to_hump

m_config = {
    "targetProject": "",
    "templates": [
        {
            "templateFile": "model.ftl",
            "targetPath": "apps/sys/model/",
            "targetFileName": "{{table.tableName}}.py",
            "selected": True,
            "covered": True,
            "encoding": 'utf-8'
        }
    ]
}


def uncap_first(text):
    return text[0:1].lower() + text[1:len(text)]


def genCode(tables, config):
    """
    生成代码
    """
    env = Environment(loader=FileSystemLoader('generator/templates'))
    env.filters['uncap_first'] = uncap_first
    env.filters['underline_to_hump'] = underline_to_hump
    templates = config['templates']
    for table in tables:
        templateData = {}
        templateData.update(config)
        templateData.update({"table": table})
        for item in templates:
            if not item.get("selected", False):
                break
            template = env.get_template(item['templateFile'])
            path = config['targetProject'] + item['targetPath']
            # 配置参数替换-模板引擎
            path = env.from_string(path).render(templateData)
            # 替换包名为目录
            path = path.replace(".", "/")
            if not os.path.exists(path):
                os.makedirs(path)
            # 配置参数替换-模板引擎
            targetFileName = env.from_string(item['targetFileName']).render(templateData)
            dist = path + targetFileName

            if os.path.exists(dist):
                if item.get("covered", False):
                    with open(dist, 'w', encoding=item.get("encoding")) as f:
                        html = template.render(templateData)
                        f.write(html)
                        print(f"{templateData['table']['tableName']}表代码生成成功-覆盖：{dist}")
                else:
                    print(f"{dist}文件已存在，不覆盖")
            else:
                with open(dist, 'w', encoding=item['encoding']) as f:
                    html = template.render(templateData)
                    f.write(html)
                    print(f"{templateData['table']['tableName']}表代码生成成功-新生成：{dist}")
    return 1


class CodeGenerator:
    def __init__(self, engine=None):
        self.engine = engine
        if engine:
            self.init_engine(engine)

    def init_engine(self, engine):
        self.engine = engine

    def build(self, tableName=None, model=1):
        metadata_obj = MetaData()
        metadata_obj.reflect(bind=self.engine, only=[tableName])
        tables = metadata_obj.tables
        m_tables = []
        for table in tables.values():
            columns = []
            m_table = {
                "tableName": table.name,
                "comment": table.comment,
                "columns": columns
            }
            for col in table.columns:
                m_type = str(col.type.get_dbapi_type)
                # <bound method Integer.get_dbapi_type of INTEGER(display_width=11)>
                # <bound method String.get_dbapi_type of VARCHAR(length=32)>
                # <bound method DateTime.get_dbapi_type of DATETIME()>
                r = re.findall('.+method (.+)\.get_dbapi_type', m_type)
                m_type = r[0]
                columns.append({
                    "name": col.name,
                    "comment": col.comment,
                    "primaryKey": col.primary_key,
                    "nullable": col.nullable,
                    "default": col.default,
                    "index": col.index,
                    "unique": col.unique,
                    "autoincrement": col.autoincrement,
                    "length": getattr(col.type, 'display_width', getattr(col.type, 'length', None)),
                    "type": m_type
                })
            m_tables.append(m_table)
            print(json.dumps(m_table, sort_keys=False, ensure_ascii=False))
        genCode(m_tables, m_config)
